home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Games / Soundboard / GWLayers.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  33.4 KB  |  1,233 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        GWLayers.c
  6. ** Written by:  Eric Soldan and Forrest Tanaka
  7. **
  8. ** Copyright © 1989-1993 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. /* This is an implementation of off-screen GWorld handling.  This particular
  21. ** implementation uses GWorlds in a hierarchical manner, with each layer in
  22. ** the hierarchy having its own tasks to handle at its specific level.
  23. ** The advantage to this is that it can conform to many applications.  Each
  24. ** application may need a different number of layers, and each layer may
  25. ** need to perform a different kind of operation.  By having an unlimited
  26. ** number of layers, and by having each layer handle its own application
  27. ** specific tasks, off-screen GWorld handling can be standardized.
  28. **
  29. ** A common use for off-screen stuff is to move an object around in a 
  30. ** window over a background.  To accomplish this, we need 3 layers.
  31. ** These are:
  32. **
  33. ** 1) The window layer.  This layer transfers a rectangle of pixels from
  34. **    the middle layer into the window layer, once the middle layer is ready.
  35. **    The rectangle transferred would be large enough to cover the old
  36. **    location and the new location, thus moving the piece without having
  37. **    to turn it off in the old location as a separate step.  This gives a
  38. **    very smooth appearance when moving an object.
  39. ** 2) A middle layer that is used to apply the object being moved to the
  40. **    background plus removing the object from the old location.  Once these
  41. **    two tasks are done, the off-screen work area is ready to be transferred
  42. **    to the window layer.
  43. ** 3) A background image against which the object moves.  This is used to
  44. **    restore the middle layer at the location where the object being moved
  45. **    was last at.
  46. **
  47. ** The top layer object relates to the window, and therefore we don't need an
  48. ** off-screen GWorld for it.  A call to create this layer might look like the below:
  49. **
  50. ** err = NewLayer(&windowLayer,   Layer object handle is returned here.
  51. **                nil,            Top layer, so there is no above layer.
  52. **                nil,            Uses default layer procedure.
  53. **                window,         Window used by the layer object.
  54. **                0,              Desired depth (0 for screen depth).
  55. **                0);             Custom layer init data, if any.
  56. **
  57. ** If NewLayer succeeds, the layer object handle is returned in windowLayer.
  58. ** If it fails, nil is returned in windowLayer, plus an error is returned.
  59. ** If windowLayer is successfully created, then we can proceed to create the
  60. ** next two layers.  In the case below, we are creating an off-screen layer
  61. ** that has a pixmap the same size and depth as windowLayer.  If this is
  62. ** what we want for the middle layer, then we can again use the default
  63. ** LayerProc for the kLayerInit message.  All we need to do is to call the
  64. ** default layerProc with a kLayerInit message.  We want the standard
  65. ** action for initialization, but we want our own update action.  That's
  66. ** why we have a custom layerProc for the middle layer.  The call would look
  67. ** something like the below:
  68. **
  69. ** err = NewLayer(&middleLayer,     Layer object handle is returned here.
  70. **                windowLayer,      Layer above this layer.
  71. **                MiddleLayerProc,  Custom layerProc.
  72. **                nil,              Create a pixmap for layer.
  73. **                0,                Pixmap created as same size/depth as above layer.
  74. **                0);
  75. **
  76. ** The background layer would be created similarly.  When you are finished with
  77. ** the layers, you can dispose of them one at a time with DisposeLayer, or you
  78. ** can dispose of all of them in the layer chain with DisposeThisAndBelowLayers.
  79. **
  80. ** Inserting a layer is done by position, and not by which layer it goes above
  81. ** or below.  The reason for this is that the layer positions are most likely
  82. ** absolute, and therefore it is better to indicate their position with an
  83. ** absolute number instead of always relating it to some other layer.  If it
  84. ** is necessary to insert a layer specifically above or below some other layer,
  85. ** it would be done as follows:
  86. **         InsertLayer(newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  87. **         InsertLayer(newLayer, belowLayer, GetLayerPosition(belowLayer));
  88. **
  89. ** The sample applications DTS.Draw and Kibitz uses the off-screen layer code.
  90. ** For a sample usage, see the file Window2.c in DTS.Draw, or Offscreen.c in Kibitz.
  91. */
  92.  
  93.  
  94.  
  95. /*****************************************************************************/
  96.  
  97.  
  98.  
  99. #ifndef __ERRORS__
  100. #include <Errors.h>
  101. #endif
  102.  
  103. #ifndef __GESTALTEQU__
  104. #include <GestaltEqu.h>
  105. #endif
  106.  
  107. #ifndef __GWLAYERS__
  108. #include "GWLayers.h"
  109. #endif
  110.  
  111. #ifndef __RESOURCES__
  112. #include <Resources.h>
  113. #endif
  114.  
  115. #ifndef __TRAPS__
  116. #include <Traps.h>
  117. #endif
  118.  
  119. #ifndef __WINDOWS__
  120. #include <Windows.h>
  121. #endif
  122.  
  123. #define kQDOriginal 0
  124.  
  125. static OSErr    DefaultLayerInit(LayerObj theLayer);
  126. static OSErr    DefaultLayerUpdate(LayerObj theLayer);
  127. static OSErr    DefaultLayerDispose(LayerObj theLayer);
  128.  
  129. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds);
  130. static void        KillLayerWorld(LayerObj theLayer);
  131. static void        SmartGetGWorld(CGrafPtr *port, GDHandle *gdh);
  132. static void        SmartSetGWorld(CGrafPtr port, GDHandle gdh);
  133. static short    GetQDVersion(void);
  134. static short    GetSystemVersion(void);
  135. static short    NumToolboxTraps(void);
  136. static Boolean    TrapExists(short theTrap);
  137. static TrapType    GetTrapType(short theTrap);
  138.  
  139.  
  140.  
  141. /*****************************************************************************/
  142. /*****************************************************************************/
  143.  
  144. #ifdef applec
  145. #pragma segment ATGGWLayers
  146. #endif
  147.  
  148. /*****************************************************************************/
  149. /*****************************************************************************/
  150.  
  151.  
  152.  
  153. OSErr    NewLayer(LayerObj *newLayer, LayerObj aboveLayer, LayerProc theProc,
  154.                  GrafPtr basePort, short depth, unsigned long theData)
  155. {
  156.     OSErr        err;
  157.     LayerRecPtr    lptr;
  158.     CGrafPtr    scratchPort;
  159.     GDHandle    baseGDevice;
  160.  
  161.     *newLayer = (LayerObj)NewHandleClear(sizeof(LayerRec));
  162.     err = MemError();
  163.     if (err) return(err);
  164.         /* If not enough memory for layer object, return nil and error. */
  165.  
  166.     SmartGetGWorld(&scratchPort, &baseGDevice);
  167.     if (!theProc)
  168.         theProc = DefaultLayerProc;
  169.             /* If layer proc is nil, then they want the default behavior. */
  170.  
  171.     lptr = **newLayer;
  172.     lptr->layerPort     = basePort;
  173.     lptr->layerGDevice  = baseGDevice;
  174.     lptr->layerDepth    = depth;
  175.     lptr->xferMode      = srcCopy;
  176.     lptr->layerProc     = theProc;
  177.     lptr->layerData     = theData;
  178.         /* Layer object is now initialized, except for layers that need a GWorld
  179.         ** created.  This will occur when the layer proc is called with an
  180.         ** initialization message.  (All fields not explicitly set are 0.) */
  181.  
  182.     InsertLayer(*newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  183.         /* Connect the layer to the layer chain.  The default initialization
  184.         ** behavior may need this, as it may create a GWorld of the same size
  185.         ** as the above layer.  If it isn't connected to the layer chain, then
  186.         ** there is no above layer. */
  187.  
  188.     err = (*theProc)(*newLayer, kLayerInit);
  189.     if (err) {
  190.         DisposeLayer(*newLayer);
  191.         *newLayer = nil;
  192.             /* There wasn't enough memory to create the off-screen GWorld, so
  193.             ** dispose of the layer object.  Since we failed, we need to return
  194.             ** nil and the error. */
  195.     }
  196.  
  197.     return(err);
  198. }
  199.  
  200.  
  201.  
  202. /*****************************************************************************/
  203.  
  204.  
  205.  
  206. void    DetachLayer(LayerObj theLayer)
  207. {
  208.     LayerObj    aboveLayer, belowLayer;
  209.  
  210.     if (theLayer) {
  211.         aboveLayer = (*theLayer)->aboveLayer;
  212.         belowLayer = (*theLayer)->belowLayer;
  213.         if (aboveLayer)
  214.             (*aboveLayer)->belowLayer = belowLayer;
  215.         if (belowLayer)
  216.             (*belowLayer)->aboveLayer = aboveLayer;
  217.         (*theLayer)->aboveLayer = (*theLayer)->belowLayer = nil;
  218.     }
  219. }
  220.  
  221.  
  222.  
  223. /*****************************************************************************/
  224.  
  225.  
  226.  
  227. OSErr    DisposeLayer(LayerObj theLayer)
  228. {
  229.     OSErr    err;
  230.  
  231.     err = noErr;
  232.     if (theLayer) {
  233.         err = (*((*theLayer)->layerProc))(theLayer, kLayerDispose);
  234.         DetachLayer(theLayer);
  235.         DisposeHandle((Handle)theLayer);
  236.     }
  237.  
  238.     return(err);
  239. }
  240.  
  241.  
  242.  
  243. /*****************************************************************************/
  244.  
  245.  
  246.  
  247. OSErr    DisposeThisAndBelowLayers(LayerObj theLayer)
  248. {
  249.     OSErr    err, err2;
  250.  
  251.     err = noErr;
  252.     if (theLayer) {
  253.         err2 = DisposeThisAndBelowLayers((*theLayer)->belowLayer);
  254.         err  = DisposeLayer(theLayer);
  255.         if (!err)
  256.             err = err2;
  257.     }
  258.     return(err);
  259. }
  260.  
  261.  
  262.  
  263. /*****************************************************************************/
  264.  
  265.  
  266.  
  267. short    GetLayerPosition(LayerObj theLayer)
  268. {
  269.     short    pos;
  270.  
  271.     if (!theLayer) return(0);
  272.  
  273.     for (pos = 0; (theLayer = (*theLayer)->aboveLayer) != nil; ++pos) {};
  274.     return(pos);
  275. }
  276.  
  277.  
  278.  
  279. /*****************************************************************************/
  280.  
  281.  
  282.  
  283. LayerObj    GetTopLayer(LayerObj theLayer)
  284. {
  285.     for (; (*theLayer)->aboveLayer; theLayer = (*theLayer)->aboveLayer) {};
  286.     return(theLayer);
  287. }
  288.  
  289.  
  290.  
  291. /*****************************************************************************/
  292.  
  293.  
  294.  
  295. LayerObj    GetBottomLayer(LayerObj theLayer)
  296. {
  297.     for (; (*theLayer)->belowLayer; theLayer = (*theLayer)->belowLayer) {};
  298.     return(theLayer);
  299. }
  300.  
  301.  
  302.  
  303. /*****************************************************************************/
  304.  
  305.  
  306.  
  307. void    InsertLayer(LayerObj theLayer, LayerObj referenceLayer, short pos)
  308. {
  309.     LayerObj    aboveLayer, belowLayer;
  310.     short        i;
  311.  
  312.     if (theLayer) {
  313.         if (theLayer == referenceLayer) {
  314.             /* If theLayer layer is the same as referenceLayer... */
  315.  
  316.             belowLayer = (*theLayer)->belowLayer;
  317.             if (belowLayer)
  318.                 referenceLayer = belowLayer;
  319.             aboveLayer = (*theLayer)->aboveLayer;
  320.             if (aboveLayer)
  321.                 referenceLayer = aboveLayer;
  322.                     /* Try to make the reference layer not the same as theLayer.
  323.                     ** If it is the same as theLayer, then when theLayer is
  324.                     ** removed from the old hierarchy, we lose the ability to re-add
  325.                     ** it to the hierarchy in a new location. */
  326.         }
  327.  
  328.         DetachLayer(theLayer);
  329.             /* Remove layer from its old hierarchy, if any. */
  330.  
  331.         if (!referenceLayer) return;
  332.             /* If there isn't a valid alternative reference, then theLayer
  333.             ** IS the hierarchy and no action is taken. */
  334.  
  335.         aboveLayer = nil;
  336.         belowLayer = GetTopLayer(referenceLayer);
  337.             /* aboveLayer now nil.  belowLayer now is top layer.  These
  338.             ** are the correct values if the layer being added is to be
  339.             ** the new top layer.  This will be the case if pos is 0.
  340.             ** We now walk the linked list pos number of times to get the
  341.             ** correct position.  We also terminate if we reach the end
  342.             ** of the linked list, no matter what pos is.  This will allow
  343.             ** values of pos that are too big to insert the layer at the
  344.             ** end of the linked list. */
  345.  
  346.         for (i = 0; ((belowLayer) && (i != pos)); ++i) {
  347.             aboveLayer = belowLayer;
  348.             belowLayer = (*belowLayer)->belowLayer;
  349.         }
  350.             /* We now have correct values for aboveLayer and belowLayer.  Note that
  351.             ** these values may be nil, which would be correct. */
  352.         (*theLayer)->aboveLayer = aboveLayer;
  353.         if (aboveLayer)
  354.             (*aboveLayer)->belowLayer = theLayer;
  355.         (*theLayer)->belowLayer = belowLayer;
  356.         if (belowLayer)
  357.             (*belowLayer)->aboveLayer = theLayer;
  358.     }
  359. }
  360.  
  361.  
  362.  
  363. /*****************************************************************************/
  364.  
  365.  
  366.  
  367. /*****************************************************************************/
  368.  
  369.  
  370.  
  371. OSErr    UpdateLayer(LayerObj theLayer)
  372. {
  373.     OSErr    err;
  374.  
  375.     err = noErr;
  376.     if (theLayer) {
  377.         err = UpdateLayer((*theLayer)->belowLayer);
  378.             /* Handle the updates from the bottom up. */
  379.         if (!err)
  380.             err = (*((*theLayer)->layerProc))(theLayer, kLayerUpdate);
  381.                 /* Chain possible errors through each level of recursion. */
  382.     }
  383.     return(err);
  384. }
  385.  
  386.  
  387.  
  388. /*****************************************************************************/
  389.  
  390.  
  391.  
  392. Rect    GetEffectiveSrcRect(LayerObj theLayer)
  393. {
  394.     Rect    srcRect;
  395.  
  396.     if (!theLayer)
  397.         SetRect(&srcRect, 0, 0, 0, 0);
  398.     else {
  399.         srcRect = (*theLayer)->srcRect;
  400.         if (EmptyRect(&srcRect))
  401.             srcRect = ((*theLayer)->layerPort)->portRect;
  402.     }
  403.     return(srcRect);
  404. }
  405.  
  406.  
  407.  
  408. /*****************************************************************************/
  409.  
  410.  
  411.  
  412. Rect    GetEffectiveDstRect(LayerObj theLayer)
  413. {
  414.     Rect    dstRect;
  415.  
  416.     if (!theLayer)
  417.         SetRect(&dstRect, 0, 0, 0, 0);
  418.     else {
  419.         dstRect = (*theLayer)->dstRect;
  420.         if (EmptyRect(&dstRect))
  421.             dstRect = ((*theLayer)->layerPort)->portRect;
  422.     }
  423.     return(dstRect);
  424. }
  425.  
  426.  
  427.  
  428. /*****************************************************************************/
  429.  
  430.  
  431.  
  432. OSErr    DefaultLayerProc(LayerObj theLayer, short message)
  433. {
  434.     OSErr    err;
  435.  
  436.     err = noErr;
  437.     if (theLayer) {
  438.         switch (message) {        /* Dispatch to the correct default behavior. */
  439.             case kLayerInit:
  440.                 err = DefaultLayerInit(theLayer);
  441.                 break;
  442.             case kLayerDispose:
  443.                 err = DefaultLayerDispose(theLayer);
  444.                 break;
  445.             case kLayerUpdate:
  446.                 err = DefaultLayerUpdate(theLayer);
  447.                 break;
  448.             default:
  449.                 break;
  450.         }
  451.     }
  452.     return(err);
  453. }
  454.  
  455.  
  456.  
  457. /*****************************************************************************/
  458.  
  459.  
  460.  
  461. Rect    UpdateUpdateRects(LayerObj theLayer)
  462. {
  463.     Rect    lastUpdate, thisUpdate, dstRect;
  464.  
  465.     if (theLayer) {
  466.         lastUpdate = (*theLayer)->lastUpdate;
  467.         (*theLayer)->lastUpdate = thisUpdate = (*theLayer)->thisUpdate;
  468.         SetRect(&((*theLayer)->thisUpdate), 0, 0, 0, 0);
  469.  
  470.         if ((*theLayer)->includeLastUpdate) {
  471.             (*theLayer)->includeLastUpdate = false;
  472.             if (EmptyRect(&lastUpdate))
  473.                 lastUpdate = thisUpdate;
  474.             if (EmptyRect(&thisUpdate))
  475.                 thisUpdate = lastUpdate;
  476.             UnionRect(&thisUpdate, &lastUpdate, &thisUpdate);
  477.                 /* We are going to update the last and current update rects.
  478.                 ** This will allow the appearance of movement for a foreground
  479.                 ** object.  The old location is cleared, plus the new location
  480.                 ** is updated. */
  481.             dstRect = GetEffectiveDstRect(theLayer);
  482.             SectRect(&thisUpdate, &dstRect, &thisUpdate);
  483.         }
  484.     }
  485.     else SetRect(&thisUpdate, 0, 0, 0, 0);
  486.  
  487.     return(thisUpdate);
  488. }
  489.  
  490.  
  491.  
  492. /*****************************************************************************/
  493.  
  494.  
  495.  
  496. void    InvalLayer(LayerObj theLayer, Rect invalRect, Boolean includeLastUpdate)
  497. {
  498.     Rect        thisUpdate, srcRect, dstRect;
  499.     LayerObj    belowLayer;
  500.     short        ow, oh;
  501.     long        dw, dh, sw, sh;
  502.  
  503.     if (theLayer) {
  504.         belowLayer = (*theLayer)->belowLayer;
  505.         dstRect    = GetEffectiveDstRect(theLayer);
  506.  
  507.         SectRect(&dstRect, &invalRect, &invalRect);
  508.         if (!EmptyRect(&invalRect)) {                /* If there is something to invalidate... */
  509.             thisUpdate = (*theLayer)->thisUpdate;    /* There may be a prior unhandled update... */
  510.             if (EmptyRect(&thisUpdate))
  511.                 thisUpdate = invalRect;                /* UnionRect doesn't */
  512.             UnionRect(&thisUpdate, &invalRect, &(*theLayer)->thisUpdate);    /* like empty rects. */
  513.  
  514.             if (belowLayer) {
  515.                 /* If we have a below layer, then pass the update down.  The effectiveSrcRct
  516.                 ** rect for the below layer may be a different size than the effectiveDstRct.
  517.                 ** If this is the case, we want to scale invalRect to invalidate a proportional
  518.                 ** area in the below layer. */
  519.  
  520.                 srcRect = GetEffectiveSrcRect(belowLayer);
  521.  
  522.                 dw = dstRect.right  - dstRect.left;        /* Calculate widths and heights for */
  523.                 dh = dstRect.bottom - dstRect.top;        /* srcRect and dstRect. */
  524.                 sw = srcRect.right  - srcRect.left;
  525.                 sh = srcRect.bottom - srcRect.top;
  526.  
  527.                 OffsetRect(&invalRect, -dstRect.left, -dstRect.top);
  528.                     /* We want to align the upper-left corner of the srcRect and dstRect
  529.                     ** so that the scaling also aligns the invalRect into the correct
  530.                     ** place in the below layer's effectiveSrcRect.  invalRect is now
  531.                     ** positioned relative to a dstRect with a upper-left corner of 0,0. */
  532.  
  533.                 if (dw != sw) {        /* Width dstRect different than srcRect. */
  534.                     ow = invalRect.right  - invalRect.left;
  535.                     invalRect.left  = (short)((invalRect.left  * sw) / dw);
  536.                     invalRect.right = (short)((invalRect.right * sw) / dw);
  537.                     if ((((invalRect.right  - invalRect.left) * dw) / sw) != ow)
  538.                         ++invalRect.right;
  539.                             /* We can possibly lose a fraction of a pixel on the right edge when
  540.                             ** scaling the invalRect.  It won't hurt if we inval just a bit too
  541.                             ** much, whereas invalidating too little is a bad thing. */
  542.                 }
  543.  
  544.                 if (dh != sh) {        /* Height dstRect different than srcRect. */
  545.                     oh = invalRect.bottom - invalRect.top;
  546.                     invalRect.top    = (short)((invalRect.top    * sh) / dh);
  547.                     invalRect.bottom = (short)((invalRect.bottom * sh) / dh);
  548.                     if ((((invalRect.bottom - invalRect.top ) * dh) / sh) != oh)
  549.                         ++invalRect.bottom;
  550.                 }
  551.  
  552.                 OffsetRect(&invalRect, srcRect.left, srcRect.top);
  553.                     /* Displace the new invalRect correctly relative to the srcRect. */
  554.             }
  555.         }
  556.  
  557.         if (includeLastUpdate)
  558.             (*theLayer)->includeLastUpdate = true;
  559.                 /* If requested to update last position as well, flag it. */
  560.  
  561.         InvalLayer(belowLayer, invalRect, includeLastUpdate);
  562.             /* Invalidate the below layer with the new (possibly scaled) invalRect. */
  563.     }
  564. }
  565.  
  566.  
  567. /*****************************************************************************/
  568.  
  569.  
  570.  
  571. void    SetLayerWorld(LayerObj theLayer)
  572. {
  573.     CGrafPtr    keepPort;
  574.     GDHandle    keepGDevice;
  575.  
  576.     /* This is a convenient call for setting a GWorld, while remembering what
  577.     ** the previous GWorld was.  This should be balanced with a call to
  578.     ** ResetLayerWorld.  A count of how many times this is called is kept
  579.     ** so that the old GWorld is cached only if SetLayerWorld is currently
  580.     ** in balance with ResetLayerWorld.  This keeps the oldest kept GWorld
  581.     ** from being overwritten by subsequent calls. */
  582.  
  583.     if (theLayer) {
  584.         if (!(*theLayer)->cachedCount++) {
  585.             SmartGetGWorld(&keepPort, &keepGDevice);
  586.             (*theLayer)->cachedPort    = keepPort;
  587.             (*theLayer)->cachedGDevice = keepGDevice;
  588.         }
  589.         SmartSetGWorld((CGrafPtr)(*theLayer)->layerPort, (*theLayer)->layerGDevice);
  590.         LockLayerWorld(theLayer);
  591.     }
  592. }
  593.  
  594.  
  595.  
  596. /*****************************************************************************/
  597.  
  598.  
  599.  
  600. void    ResetLayerWorld(LayerObj theLayer)
  601. {
  602.     /* This is used to undo a call to SetLayerWorld.  Calls to ResetLayerWorld
  603.     ** should be balanced with previous calls to SetLayerWorld. */
  604.  
  605.     if (theLayer) {
  606.         UnlockLayerWorld(theLayer);
  607.         if (!--(*theLayer)->cachedCount)
  608.             SmartSetGWorld((*theLayer)->cachedPort, (*theLayer)->cachedGDevice);
  609.     }
  610. }
  611.  
  612.  
  613.  
  614. /*****************************************************************************/
  615.  
  616.  
  617.  
  618. void    LockLayerWorld(LayerObj theLayer)
  619. {
  620.     Handle    bitmap;
  621.  
  622.     /* This is a convenient way to lock down the pixels for a layer's GWorld.
  623.     ** A locked count is kept to make sure that the GWorld is locked only the
  624.     ** first time this is called.  Calls to LockLayerWorld will most likely
  625.     ** be balanced by calls to UnlockLayerWorld, but not necessarily.  It may
  626.     ** be desirable to keep a GWorld call locked.  In this case, right after
  627.     ** creating the layer (and indirectly its GWorld), call LockLayerWorld.
  628.     ** This will initially lock it.  Subsequent calls would be balanced, and
  629.     ** therefore there will always be one more LockLayerWorld call than
  630.     ** UnlockLayerWorld calls.  This will keep it locked. */
  631.  
  632.     if (theLayer) {
  633.         if ((*theLayer)->layerOwnsPort) {
  634.             if (!(*theLayer)->lockedCount++) {
  635.                 bitmap = (*theLayer)->layerBitmap;
  636.                 if (bitmap) {
  637.                     HLock(bitmap);
  638.                     (*theLayer)->layerPort->portBits.baseAddr = *bitmap;
  639.                 }
  640.                 else
  641.                     LockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  642.             }
  643.         }
  644.     }
  645. }
  646.  
  647.  
  648.  
  649. /*****************************************************************************/
  650.  
  651.  
  652.  
  653. void    UnlockLayerWorld(LayerObj theLayer)
  654. {
  655.     /* This undoes what LockLayerWorld does.  Calls to UnlockLayerWorld will
  656.     ** generally be balanced with calls to LockLayerWorld. */
  657.  
  658.     if (theLayer) {
  659.         if ((*theLayer)->layerOwnsPort) {
  660.             if (!--(*theLayer)->lockedCount) {
  661.                 if ((*theLayer)->layerBitmap)
  662.                     HUnlock((*theLayer)->layerBitmap);
  663.                 else
  664.                     UnlockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  665.             }
  666.         }
  667.     }
  668. }
  669.  
  670.  
  671.  
  672. /*****************************************************************************/
  673.  
  674.  
  675.  
  676. RgnHandle    ScreenDepthRegion(short depth)
  677. {
  678.     RgnHandle        retRgn, tmpRgn;
  679.     GDHandle        device;
  680.     PixMapHandle    pmap;
  681.     Rect            rct;
  682.     GrafPtr            mainPort;
  683.  
  684.     retRgn = NewRgn();
  685.  
  686.     if (GetQDVersion() == kQDOriginal) {
  687.         if (depth == 1) {
  688.             GetWMgrPort(&mainPort);
  689.             rct = mainPort->portRect;
  690.             RectRgn(retRgn, &rct);
  691.         }
  692.     }
  693.     else {
  694.         tmpRgn = NewRgn();
  695.         for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  696.             if (
  697.                 (TestDeviceAttribute(device, screenDevice)) &&
  698.                 (TestDeviceAttribute(device, screenActive))
  699.             ) {
  700.                 pmap = (*device)->gdPMap;
  701.                 if ((*pmap)->pixelSize >= depth) {
  702.                     rct = (*device)->gdRect;
  703.                     RectRgn(tmpRgn, &rct);
  704.                     UnionRgn(retRgn, tmpRgn, retRgn);
  705.                 }
  706.             }
  707.         }
  708.         DisposeRgn(tmpRgn);
  709.     }
  710.  
  711.     return(retRgn);
  712. }
  713.  
  714.  
  715.  
  716. /*****************************************************************************/
  717.  
  718.  
  719.  
  720. CIconHandle    ReadCIcon(short iconID)
  721. {
  722.     Handle    hndl;
  723.  
  724.     if (TrapExists(_PlotCIcon))
  725.         return(GetCIcon(iconID));
  726.  
  727.     hndl = GetResource('cicn', iconID);
  728.     DetachResource(hndl);
  729.     return((CIconHandle)hndl);
  730. }
  731.  
  732.  
  733.  
  734. /*****************************************************************************/
  735.  
  736.  
  737.  
  738. void    KillCIcon(CIconHandle icon)
  739. {
  740.     if (!icon) return;
  741.  
  742.     if (TrapExists(_PlotCIcon))
  743.         DisposeCIcon(icon);
  744.     else
  745.         DisposeHandle((Handle)icon);
  746. }
  747.  
  748.  
  749.  
  750. /*****************************************************************************/
  751.  
  752.  
  753.  
  754. void    DrawCIcon(CIconHandle icon, Rect destRect)
  755. {
  756.     WindowPtr    curPort;
  757.     short        depth;
  758.  
  759.     if (!icon) return;
  760.  
  761.     if (TrapExists(_PlotCIcon)) {
  762.         depth = 8;
  763.         if (GetSystemVersion() < 0x0700) {
  764.             depth = 1;
  765.             GetPort(&curPort);
  766.             if (curPort->portBits.rowBytes & 0x8000)
  767.                 depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  768.         }
  769.     }
  770.     else depth = 1;
  771.  
  772.     if (depth > 1)
  773.         PlotCIcon(&destRect, icon);
  774.     else
  775.         DrawCIconByDepth(icon, destRect, 1, true);
  776. }
  777.  
  778.  
  779.  
  780. /*****************************************************************************/
  781.  
  782.  
  783.  
  784. void    DrawCIconNoMask(CIconHandle icon, Rect destRect)
  785. {
  786.     Rect    iconRect;
  787.     char    oldMask[128], *mptr;
  788.     short    maskSize, i;
  789.  
  790.     if (!icon) return;
  791.  
  792.     mptr = (Ptr)(*icon)->iconMaskData;
  793.     iconRect = (*icon)->iconPMap.bounds;
  794.     maskSize = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
  795.     for (i = 0; i < maskSize; ++i) {
  796.         oldMask[i] = mptr[i];
  797.         mptr[i] = 0xFF;
  798.     }
  799.     DrawCIcon(icon, destRect);
  800.     mptr = (Ptr)(*icon)->iconMaskData;
  801.     for (i = 0; i < maskSize; ++i) mptr[i] = oldMask[i];
  802. }
  803.  
  804.  
  805.  
  806. /*****************************************************************************/
  807.  
  808.  
  809.  
  810. void    DrawCIconByDepth(CIconHandle icon, Rect destRect, short depth, Boolean useMask)
  811. {
  812.     GrafPtr        curPort;
  813.     char        savedIconState;
  814.     char        savedDataState;
  815.     short        offset;
  816.     BitMapPtr    bmap;
  817.     Rect        iconRect;
  818.  
  819.     if (!icon) return;
  820.  
  821.     GetPort(&curPort);
  822.  
  823.     if (!depth) {
  824.         if (!(curPort->portBits.rowBytes & 0x8000))
  825.             depth = 1;
  826.         else
  827.             depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  828.     }
  829.  
  830.     savedIconState = HGetState((Handle)icon);        /* Lock down things. */
  831.     HLock((Handle)icon);
  832.     if (depth > 1) {
  833.         savedDataState = HGetState((*icon)->iconData);
  834.         HLock((*icon)->iconData);
  835.         (*icon)->iconPMap.baseAddr = *((*icon)->iconData);
  836.             /* Point the icon's pixMap at the color icon data. */
  837.     }
  838.  
  839.     iconRect = (*icon)->iconPMap.bounds;
  840.         /* Find out the dimensions of the icon. */
  841.  
  842.     (*icon)->iconMask.baseAddr = (Ptr)(*icon)->iconMaskData;
  843.         /* Point the mask's bitMap at the mask data. */
  844.  
  845.     offset  = iconRect.bottom - iconRect.top;
  846.     offset *= (*icon)->iconMask.rowBytes;
  847.     (*icon)->iconBMap.baseAddr = (*icon)->iconMask.baseAddr + offset;
  848.         /* Point the icon's bitMap at the b/w icon data. */
  849.  
  850.     bmap = (depth == 1) ? (BitMapPtr)&((*icon)->iconBMap) : (BitMapPtr)&((*icon)->iconPMap);
  851.     if (useMask)
  852.         CopyMask(bmap, &((*icon)->iconMask), &curPort->portBits, &iconRect, &iconRect, &destRect);
  853.     else
  854.         CopyBits(bmap, &curPort->portBits, &iconRect, &destRect, srcCopy, nil);
  855.  
  856.     HSetState((Handle)icon, savedIconState);        /* Unlock things. */
  857.     if (depth > 1)
  858.         HSetState((*icon)->iconData, savedDataState);
  859. }
  860.  
  861.  
  862.  
  863. /*****************************************************************************/
  864. /*****************************************************************************/
  865. /*****************************************************************************/
  866.  
  867.  
  868.  
  869. static OSErr    DefaultLayerInit(LayerObj theLayer)
  870. {
  871.     LayerObj    aboveLayer;
  872.     GWorldPtr    layerWorld;        /* GWorld for this layer. */
  873.     Rect        parentRect;        /* Rectangle of parent in global coordinates. */
  874.     GrafPtr        parentPort;        /* Parent layer's GrafPort. */
  875.     GDHandle    parentGDevice;    /* Parent layer's GDevice. */
  876.     CGrafPtr    keepPort;        /* Saved GrafPort. */
  877.     GDHandle    keepGDevice;    /* Saved GDevice. */
  878.     Point        org;
  879.     OSErr        err;
  880.     short        depth;
  881.  
  882.     err = noErr;
  883.     if (theLayer) {
  884.         if (!(*theLayer)->layerPort) {
  885.  
  886.             aboveLayer = (*theLayer)->aboveLayer;
  887.             if (aboveLayer) {
  888.                 /* The default behavior is to create a GWorld the same size
  889.                 ** as the above layer, if there is one.  If there isn't an above
  890.                 ** layer and we were expected to create a GWorld, we have problems.
  891.                 ** This situation can't be resolved and is handled as a paramErr. */
  892.  
  893.                 if (!((*theLayer)->layerDepth))
  894.                     (*theLayer)->layerDepth = (*aboveLayer)->layerDepth;
  895.  
  896.                 SmartGetGWorld(&keepPort, &keepGDevice);        /* Keep the GWorld. */
  897.  
  898.                 parentPort    = (*aboveLayer)->layerPort;
  899.                 parentGDevice = (*aboveLayer)->layerGDevice;
  900.                     /* Grab the parent layer's GrafPort and GDevice. */
  901.     
  902.                 SmartSetGWorld((CGrafPtr)parentPort, parentGDevice);
  903.                 parentRect = GetEffectiveDstRect(aboveLayer);
  904.                     /* The default behavior is to use the portRect of the above
  905.                     ** port.  This behavior can be overridden if desired by setting
  906.                     ** dstRect.  dstRect is initialized to be empty, but if
  907.                     ** it is specifically set, then this layer should map into
  908.                     ** just the dstRect and not the portRect.  This is useful if
  909.                     ** the off-screen image is to be displayed in only a portion
  910.                     ** of a window. */
  911.  
  912.                 org.h = parentRect.left;
  913.                 org.v = parentRect.top;
  914.  
  915.                 LocalToGlobal(((Point *)&parentRect) + 0);
  916.                 LocalToGlobal(((Point *)&parentRect) + 1);
  917.                     /* Put the parent layer's destination rect in global coordinates. */
  918.     
  919.                 if (GetQDVersion())
  920.                     err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &parentRect, nil, nil, 0);
  921.                         /* Create the GWorld for this layer.  It will be created with the
  922.                         ** requested depth.  If the requested depth is 0, then it will be
  923.                         ** created with a depth great enough for the deepest monitor the
  924.                         ** parentRect intersects. */
  925.                 else
  926.                     err = MakeLayerWorld(&layerWorld, theLayer, parentRect);
  927.                         /* Create a bitmap for those systems without GWorlds. */
  928.  
  929.                 if (err == noErr) {
  930.                     (*theLayer)->layerOwnsPort = true;
  931.                     SetPort((*theLayer)->layerPort = (GrafPtr)layerWorld);
  932.                         /* Save the new GWorld in the layer object. */
  933.                     SetOrigin(org.h, org.v);
  934.                         /* Set the origin so that this GWorld maps directly into the
  935.                         ** area to be copied into (dstRect or portRect) for the
  936.                         ** above layer. */
  937.  
  938.                     if (!((*theLayer)->layerDepth)) {
  939.                         if (((GrafPtr)layerWorld)->portBits.rowBytes & 0x8000)
  940.                             depth = (*(((CGrafPtr)layerWorld)->portPixMap))->pixelSize;
  941.                         else
  942.                             depth = 1;
  943.                         (*theLayer)->layerDepth = depth;
  944.                     }
  945.                 }
  946.  
  947.                 SmartSetGWorld(keepPort, keepGDevice);        /* Restore the kept GWorld. */
  948.             }
  949.             else {
  950.                 err = paramErr;
  951.                     /* We were expected to create an off-screen GWorld of the
  952.                     ** same size as the above layer, but we didn't have an above
  953.                     ** layer.  This is an error.  The parameters passed to NewLayer
  954.                     ** were inappropriate for the situation, so return a paramErr. */
  955.             }
  956.         }
  957.     }
  958.  
  959.     return(err);
  960. }
  961.  
  962.  
  963.  
  964. /*****************************************************************************/
  965.  
  966.  
  967.  
  968. static OSErr    DefaultLayerUpdate(LayerObj theLayer)
  969. {
  970.     LayerObj    belowLayer;
  971.     GrafPtr        belowPort, thisPort;
  972.     GDHandle    thisGDevice;
  973.     CGrafPtr    keepPort;
  974.     GDHandle    keepGDevice;
  975.     Rect        thisUpdate, belowRect, thisRect;
  976.     short        xfer;
  977.     RgnHandle    rgn;
  978.  
  979.     /* The default update behavior is to copy the area to be updated from the
  980.     ** below layer into the indicated layer.  We only need to update layer if
  981.     ** there is a below layer.  The bottom-most layer update doesn't do anything.
  982.     ** As a default, the bottom-most layer is considered background and does not
  983.     ** get updated. */
  984.  
  985.     if (theLayer) {
  986.         belowLayer = (*theLayer)->belowLayer;
  987.         if (belowLayer) {
  988.             /* Get this layer's GWorld and below layer's port. */
  989.             thisPort    = (*theLayer)->layerPort;
  990.             thisGDevice = (*theLayer)->layerGDevice;
  991.             belowPort   = (*belowLayer)->layerPort;
  992.  
  993.             /* Save current GWorld and set the parent's GWorld. */
  994.             SmartGetGWorld(&keepPort, &keepGDevice);
  995.             SmartSetGWorld((CGrafPtr)thisPort, thisGDevice);
  996.  
  997.             thisUpdate = UpdateUpdateRects(theLayer);
  998.  
  999.             rgn = NewRgn();
  1000.             RectRgn(rgn, &thisUpdate);
  1001.  
  1002.             belowRect = GetEffectiveSrcRect(belowLayer);
  1003.             thisRect  = GetEffectiveDstRect(theLayer);
  1004.  
  1005.                 /* As a default behavior, we CopyBits the below layer into this layer. */
  1006.             LockLayerWorld(belowLayer);
  1007.             LockLayerWorld(theLayer);
  1008.             xfer = (*theLayer)->xferMode;
  1009.             CopyBits(&belowPort->portBits, &thisPort->portBits, &belowRect, &thisRect, xfer, rgn);
  1010.             UnlockLayerWorld(theLayer);
  1011.             UnlockLayerWorld(belowLayer);
  1012.             DisposeRgn(rgn);
  1013.  
  1014.             SmartSetGWorld(keepPort, keepGDevice);        /* Restore to the kept GWorld. */
  1015.         }
  1016.     }
  1017.     return(noErr);
  1018. }
  1019.  
  1020.  
  1021.  
  1022. /*****************************************************************************/
  1023.  
  1024.  
  1025.  
  1026. static OSErr    DefaultLayerDispose(LayerObj theLayer)
  1027. {
  1028.     GWorldPtr    theWorld;
  1029.  
  1030.     if (theLayer) {
  1031.         if ((*theLayer)->layerOwnsPort) {
  1032.             theWorld = (GWorldPtr)(*theLayer)->layerPort;
  1033.             if (theWorld) {
  1034.                 if ((*theLayer)->layerBitmap)
  1035.                     KillLayerWorld(theLayer);
  1036.                 else
  1037.                     DisposeGWorld(theWorld);
  1038.             }
  1039.         }
  1040.     }
  1041.  
  1042.     return(noErr);
  1043. }
  1044.  
  1045.  
  1046.  
  1047. /*****************************************************************************/
  1048.  
  1049.  
  1050.  
  1051. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds)
  1052. {
  1053.     GrafPtr    oldPort;
  1054.     GrafPtr    newPort;
  1055.     Handle    bitmap;
  1056.     OSErr    err;
  1057.  
  1058.     OffsetRect(&bnds, -bnds.left, -bnds.top);    /* Make sure upper-left is 0,0. */
  1059.  
  1060.     GetPort(&oldPort);        /* Need this to restore the port after OpenPort. */
  1061.  
  1062.     newPort = (GrafPtr)NewPtr(sizeof(GrafPort));        /* Allocate the grafPort. */
  1063.     err = MemError();
  1064.     if (err)
  1065.         return(err);        /* Failed to allocate the off-screen port. */
  1066.  
  1067.     /* The call to OpenPort does the following:
  1068.     ** 1) allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  1069.     ** 2) sets portBits to screenBits
  1070.     ** 3) sets portRect to screenBits.bounds, etc. (see IM I-163,164)
  1071.     ** 4) side effect: does a SetPort(&offScreen) */
  1072.  
  1073.     OpenPort(newPort);
  1074.     SetPort(oldPort);
  1075.  
  1076.         /* Now make bitmap the size of the bounds that caller supplied. */
  1077.  
  1078.     newPort->portRect = bnds;
  1079.     newPort->portBits.bounds = bnds;
  1080.     RectRgn(newPort->visRgn, &bnds);
  1081.  
  1082.     SetRectRgn(newPort->clipRgn, -32000, -32000, 32000, 32000);
  1083.         /* Avoid wide-open clipRgn, to be safe.    */
  1084.  
  1085.     /* rowBytes is size of row, it must be rounded up to an even number of bytes. */
  1086.     newPort->portBits.rowBytes = ((bnds.right - bnds.left + 15) >> 4) << 1;
  1087.  
  1088.     bitmap = NewHandle(newPort->portBits.rowBytes * (long)(bnds.bottom - bnds.top));
  1089.     err = MemError();
  1090.     if (err) {
  1091.         ClosePort(newPort);            /* Dump the visRgn and clipRgn. */
  1092.         DisposePtr((Ptr)newPort);    /* Dump the GrafPort. */
  1093.         return(err);
  1094.     }
  1095.  
  1096.     (*theLayer)->layerBitmap = bitmap;
  1097.     *layerWorld              = (GWorldPtr)newPort;
  1098.  
  1099.     return(noErr);
  1100. }
  1101.  
  1102.  
  1103.  
  1104. /*****************************************************************************/
  1105.  
  1106.  
  1107.  
  1108. static void    KillLayerWorld(LayerObj theLayer)
  1109. {
  1110.     DisposeHandle((*theLayer)->layerBitmap);
  1111.     (*theLayer)->layerBitmap = nil;
  1112.  
  1113.     ClosePort((*theLayer)->layerPort);
  1114.     DisposePtr((Ptr)(*theLayer)->layerPort);
  1115.     (*theLayer)->layerPort = nil;
  1116. }
  1117.  
  1118.  
  1119.  
  1120.  
  1121. /*****************************************************************************/
  1122.  
  1123.  
  1124.  
  1125. static void    SmartGetGWorld(CGrafPtr *port, GDHandle *gdh)
  1126. {
  1127.     if (GetQDVersion())
  1128.         GetGWorld(port, gdh);
  1129.     else {
  1130.         *gdh = nil;
  1131.         GetPort((GrafPtr *)port);
  1132.     }
  1133. }
  1134.  
  1135.  
  1136.  
  1137. /*****************************************************************************/
  1138.  
  1139.  
  1140.  
  1141. static void    SmartSetGWorld(CGrafPtr port, GDHandle gdh)
  1142. {
  1143.     if (GetQDVersion())
  1144.         SetGWorld(port, gdh);
  1145.     else
  1146.         SetPort((GrafPtr)port);
  1147. }
  1148.  
  1149.  
  1150.  
  1151. /*****************************************************************************/
  1152.  
  1153.  
  1154.  
  1155. static short    GetQDVersion()
  1156. {
  1157.     static long    gestaltResult = -1;
  1158.  
  1159.     if (gestaltResult == -1) {
  1160.         if (Gestalt(gestaltQuickdrawVersion, &gestaltResult))
  1161.             gestaltResult = 0;
  1162.     }
  1163.  
  1164.     return((gestaltResult >> 8) & 0xFF);
  1165. }
  1166.  
  1167.  
  1168.  
  1169. /*****************************************************************************/
  1170.  
  1171.  
  1172.  
  1173. static short    GetSystemVersion()
  1174. {
  1175.     static long    gestaltResult;
  1176.  
  1177.     if (!gestaltResult) {
  1178.         if (Gestalt(gestaltSystemVersion, &gestaltResult))
  1179.             gestaltResult = 0;
  1180.     }
  1181.  
  1182.     return(gestaltResult);
  1183. }
  1184.  
  1185.  
  1186.  
  1187. /*****************************************************************************/
  1188.  
  1189.  
  1190.  
  1191. static Boolean    TrapExists(short theTrap)
  1192. {
  1193.     TrapType    theTrapType;
  1194.  
  1195.     theTrapType = GetTrapType(theTrap);
  1196.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  1197.         theTrap = _Unimplemented;
  1198.  
  1199.     return(NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
  1200. }
  1201.  
  1202.  
  1203.  
  1204. /*****************************************************************************/
  1205.  
  1206.  
  1207.  
  1208. static short    NumToolboxTraps(void)
  1209. {
  1210.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  1211.         return(0x200);
  1212.     else
  1213.         return(0x400);
  1214. }
  1215.  
  1216.  
  1217.  
  1218. /*****************************************************************************/
  1219.  
  1220.  
  1221.  
  1222. static TrapType    GetTrapType(short theTrap)
  1223. {
  1224.     /* OS traps start with A0, Tool with A8 or AA. */
  1225.     if ((theTrap & 0x0800) == 0)                    /* per D.A. */
  1226.         return(OSTrap);
  1227.     else
  1228.         return(ToolTrap);
  1229. }
  1230.  
  1231.  
  1232.  
  1233.